package com.hmdp.service.impl;

import cn.hutool.json.JSONUtil;
import com.hmdp.dto.MessageCommentDTO;
import com.hmdp.dto.Result;
import com.hmdp.dto.ScrollResult;
import com.hmdp.dto.UserDTO;
import com.hmdp.entity.Blog;
import com.hmdp.entity.BlogComments;
import com.hmdp.entity.User;
import com.hmdp.mapper.BlogCommentsMapper;
import com.hmdp.service.IBlogCommentsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.service.IBlogService;
import com.hmdp.service.IUserService;
import com.hmdp.utils.UserHolder;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static com.hmdp.utils.RedisConstants.MESSAGE_COMMENT_KEY_PRE;
import static com.hmdp.utils.RedisConstants.MESSAGE_COUNT_KEY_PRE;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
public class BlogCommentsServiceImpl extends ServiceImpl<BlogCommentsMapper, BlogComments> implements IBlogCommentsService {

    @Resource
    private IUserService userService;

    @Resource
    private IBlogService blogService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 先根据前端传回的blogComments中的blogId去查看(其对应的shopId)，
     * @param blogComments
     * @return
     */
    @Override
    public Result blogComment(BlogComments blogComments, long shopId) {
        // 1.获取当前用户id
        UserDTO user = UserHolder.getUser();
        Long userId = user.getId();
        // 2.评论博客，属于一级评论，因此回复的评论id为空，点赞数为0
        Long parentId = 0L;
        // 3.设置状态Status
        Integer Status = 0;
        // 4.创建时间
        LocalDateTime createTime = LocalDateTime.now();
        // 5.更新时间
        LocalDateTime updateTime = LocalDateTime.now();

        blogComments.setUserId(userId);
        blogComments.setParentId(parentId);
        blogComments.setStatus(true);
        blogComments.setCreateTime(createTime);
        blogComments.setUpdateTime(updateTime);

        this.save(blogComments);
        return Result.ok(blogComments);
    }

    @Override
    @Transactional
    public Result blogComment(BlogComments blogComments, long shopId, long blogUserId) {
        // 1.获取当前用户id
        UserDTO user = UserHolder.getUser();
        Long userId = user.getId();
        // 2.评论博客，属于以及评论，因此恢复的评论id，点赞数为0
        Long parentId = 0L;
        // 3.设置状态Status
        Integer Status = 0;
        // 4.创建时间
        LocalDateTime createTime = LocalDateTime.now();
        // 5.更新时间
        LocalDateTime updateTime = LocalDateTime.now();
        // 6.完善BlogComments对象
        blogComments.setUserId(userId);
        blogComments.setParentId(parentId);
        blogComments.setStatus(true);
        blogComments.setCreateTime(createTime);
        blogComments.setUpdateTime(updateTime);
        // 7.讲评论对象BlogComments存放至数据库中
        this.save(blogComments);
        // 8.根据评论者的简单信息以及博文标题
        User blogUser = userService.query().eq("id", blogComments.getUserId()).one();
        Blog blog = blogService.query().eq("id", blogComments.getBlogId()).one();
        // 9.将该评论的id推送至探店博文的发表者收件箱中
        MessageCommentDTO msgCommentDTO = new MessageCommentDTO();
        msgCommentDTO.setTitle(blog.getTitle());
        msgCommentDTO.setNickname(blogUser.getNickName());
        msgCommentDTO.setIcon(blogUser.getIcon());
        msgCommentDTO.setContent(blogComments.getContent());
        msgCommentDTO.setLiked(blogComments.getLiked());
        msgCommentDTO.setCreateTime(blogComments.getCreateTime());
//        msgCommentDTO.setData(blogComments);
        stringRedisTemplate.opsForZSet().add(MESSAGE_COMMENT_KEY_PRE + blogUserId, JSONUtil.toJsonStr(msgCommentDTO), System.currentTimeMillis());
        // 10.发表者的收件箱消息数自增1
        stringRedisTemplate.opsForValue().increment(MESSAGE_COUNT_KEY_PRE + blogUserId);
        // 11.返回
        return Result.ok(msgCommentDTO);
    }

    @Override
    public Result getBlogComments(long blogId) {
        return null;
    }

    /**
     *
     * @param minTime: 上一次查询的最小时间戳
     * @param offset: 偏移量
     * @return List<>: 评论集合，minTime：本次查询的推送的最小时间戳
     */
    @Override
    public Result getBlogCommentsMessage(Long minTime, Integer offset) {
        // 1.获取当前用户id
        Long userId = UserHolder.getUser().getId();

        // 2.查询当前用户的消息收件箱(comment) ZREVRANGEBYSCORE message:comment:2 minTime 0 LIMIT offset count
        String key = MESSAGE_COMMENT_KEY_PRE + userId;
//        String key = MESSAGE_COMMENT_KEY_PRE + 2;

        Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().reverseRangeByScoreWithScores(
                key, 0, minTime, offset, 2
        ); //key min max offset count

        // 3.非空判断
        if(typedTuples == null || typedTuples.isEmpty()){
            return Result.ok("数据为空！");
        }

        // 4.解析数据：包含title、nickname、icon、content、createTime、liked
        List<MessageCommentDTO> list = new ArrayList<>(typedTuples.size()); //这里直接提取处MessageCommentDTO的JSON字符串
        long min = 0L; //当前页数的最小时间戳
        Integer os = 1; //计算score最小时间戳相同的元素个数
        for (ZSetOperations.TypedTuple<String> tuple : typedTuples){
            // 4.1.获取MessageCommentDTO对象
            MessageCommentDTO mcDTO = JSONUtil.toBean(tuple.getValue(), MessageCommentDTO.class);
            list.add(mcDTO);
            // 4.2.获取时间戳
            long time = tuple.getScore().longValue();
            // 4.3判断当前时间戳是否跟min上一个时间戳相等
            if(time == min){
                //最小时间戳不变，os自增1
                ++os;
            } else{
                min = time; //更新最小时间戳
                os = 1; //重置说是因为最小时间戳重复的元素在分页的中间
            }
        }

        // 5.封装并返回
        ScrollResult result = new ScrollResult();
        result.setList(list);
        result.setMinTime(min);
        result.setOffset(os);
        return Result.ok(result);
    }
}
